﻿using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Hopscotch.Domain.Finance;
using Hopscotch.Presentation.Common;
using Hopscotch.Presentation.Controls.DataProviders;


namespace Hopscotch.Presentation.Controls.Core
{
    /// <summary>
    /// Interaction logic for PriceControl.xaml
    /// </summary>
    public partial class PriceControl : UserControlBase, INotifyDataErrorInfo
    {
        private const string PricePropertyName = "Price";
        private const string CurrencyPropertyName = "Currency";

        private readonly ObservableCollection<CurrencyInstrument> currencyCollection;

        public PriceControl()
        {
            currencyCollection = new ObservableCollection<CurrencyInstrument>();

            Validation.AddErrorHandler(this, OnBindingValidationError);

            InitializeComponent();
        }

        void OnBindingValidationError(object sender, ValidationErrorEventArgs e)
        {
            RaiseErrorsChanged(PricePropertyName);
            RaiseErrorsChanged(CurrencyPropertyName);
        }

        //DependencyProperty(s)
        public static readonly DependencyProperty PriceProperty
            = DependencyProperty.Register(PricePropertyName, typeof(decimal), typeof(PriceControl), new PropertyMetadata(OnPriceChanged));

        public static readonly DependencyProperty IncrementProperty
            = DependencyProperty.Register("Increment", typeof(decimal), typeof(PriceControl), new PropertyMetadata(1.0M));

        public static readonly DependencyProperty CurrencyProperty
            = DependencyProperty.Register(CurrencyPropertyName, typeof(CurrencyInstrument), typeof(PriceControl), new PropertyMetadata(OnCurrencyChanged));

        public static readonly DependencyProperty CurrencyCodeProperty
            = DependencyProperty.Register("CurrencyCode", typeof(string), typeof(PriceControl), new PropertyMetadata(OnCurrencyCodeChanged));

        public static readonly DependencyProperty DataProviderProperty
            = DependencyProperty.Register("DataProvider", typeof(IPriceControlDataProvider), typeof(PriceControl), new PropertyMetadata(OnDataProviderChanged));

        //Properties	
        public decimal Price
        {
            get { return (decimal)this.GetValue(PriceProperty); }
            set { this.SetValue(PriceProperty, value); }
        }

        public decimal Increment
        {
            get { return (decimal)this.GetValue(IncrementProperty); }
            set { this.SetValue(IncrementProperty, value); }
        }

        public CurrencyInstrument Currency
        {
            get { return (CurrencyInstrument)this.GetValue(CurrencyProperty); }
            set { this.SetValue(CurrencyProperty, value); }
        }

        public string CurrencyCode
        {
            get { return (string)this.GetValue(CurrencyCodeProperty); }
            set { this.SetValue(CurrencyCodeProperty, value); }
        }

        public IPriceControlDataProvider DataProvider
        {
            get { return (IPriceControlDataProvider)this.GetValue(DataProviderProperty); }
            set { this.SetValue(DataProviderProperty, value); }
        }

        public ObservableCollection<CurrencyInstrument> Currencies
        {
            get
            {
                return currencyCollection;
            }
        }

        private void ReloadCurrencies()
        {
            currencyCollection.Clear();
            var currencies = DataProvider.GetCurrencyList();
            if (currencies == null)
                return;

            foreach (CurrencyInstrument currencyInstrument in currencies)
            {
                currencyCollection.Add(currencyInstrument);
            }
        }

        private void LoadCurrency(string code)
        {
            Currency = currencyCollection.FirstOrDefault(p => p.Code == code);
        }

        private static void OnPriceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var priceControl = obj as PriceControl;

            if (priceControl != null)
            {
                priceControl.RaiseErrorsChanged(PricePropertyName);
            }
        }

        private static void OnCurrencyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var priceControl = obj as PriceControl;
            var currency = e.NewValue as CurrencyInstrument;

            if (priceControl != null &&
                currency != null)
            {
                priceControl.CurrencyCode = currency.Code;
            }
        }

        private static void OnCurrencyCodeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var priceControl = obj as PriceControl;
            var currencyCode = e.NewValue as string;

            if (priceControl != null)
            {
                priceControl.LoadCurrency(currencyCode);
            }
        }

        private static void OnDataProviderChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var priceControl = obj as PriceControl;

            if (priceControl != null)
            {
                priceControl.ReloadCurrencies();
                priceControl.RaiseErrorsChanged(PricePropertyName);
                priceControl.RaiseErrorsChanged(CurrencyPropertyName);
            }
        }

        public override IEnumerable GetErrors(string propertyName)
        {
            if (propertyName == PricePropertyName)// || propertyName == CurrencyPropertyName)
            {
                if (DataProvider == null)
                {
                    //If the DataProvider has not been set, flag as an error
                    return this.DataProviderError;
                }

                if (Validation.GetErrors(this).Count > 0)
                {
                    var list = Validation.GetErrors(this).Select(x => x.ErrorContent).ToList();
                    return list;
                }
            }

            return null;
        }

        public override bool HasErrors
        {
            get
            {
                if (DataProvider == null)
                {
                    //If the CurrencyDataProvider has not been set, flag as an error
                    return true;
                }

                return Validation.GetHasError(this);
            }
        }

    }
}
